import "./index.scss";
import { View, Input, Button, ScrollView } from "@tarojs/components";
import { AtIcon } from "taro-ui";
import { useState, useRef, useEffect } from "react";
import { useRouter } from "@tarojs/taro";
import axios from "axios";
import { KJUR } from "jsrsasign";

function useTypewriter(speed = 30) {
  const [display, setDisplay] = useState("");
  const timer = useRef<NodeJS.Timeout | null>(null);

  const start = (newText: string, onFinish?: () => void) => {
    if (timer.current) clearTimeout(timer.current);
    setDisplay("");
    let i = 0;
    function typing() {
      setDisplay((prev) => prev + newText[i]);
      i++;
      if (i < newText.length) {
        timer.current = setTimeout(typing, speed);
      } else {
        onFinish && onFinish();
      }
    }
    if (newText) typing();
  };

  return [display, start] as const;
}

function generateToken(
  apiKey = "67db65be360b95266c69c2c5.z57eEVIxub1nvH1RNA+ueL2LVIWCBU0Y",
  expSeconds = 3600
) {
  const [id, secret] = apiKey.split(".");
  const header = { alg: "HS256", typ: "JWT" };
  const payload = {
    api_key: id,
    exp: Math.floor(Date.now() / 1000) + expSeconds,
    timestamp: Math.floor(Date.now() / 1000),
  };
  return KJUR.jws.JWS.sign(
    "HS256",
    JSON.stringify(header),
    JSON.stringify(payload),
    secret
  );
}

// ✅ 封装 localStorage 方法
const storage = {
  set(key: string, value: any) {
    localStorage.setItem(key, JSON.stringify(value));
  },
  get(key: string) {
    const item = localStorage.getItem(key);
    return item ? JSON.parse(item) : null;
  },
  remove(key: string) {
    localStorage.removeItem(key);
  },
};

import Taro from "@tarojs/taro";

export default function Chat() {
  const router = useRouter();
  const ais = router.params.ais
    ? JSON.parse(decodeURIComponent(router.params.ais))
    : {};
  const { appid, apiKey, url } = ais;

  const [input, setInput] = useState("");
  const [messages, setMessages] = useState<
    { role: "user" | "bot"; text: string; loading?: boolean }[]
  >([]);
  const [typing, setTyping] = useState(false);
  const [typeText, startType] = useTypewriter();
  const scrollRef = useRef<any>(null);

  // ✅ 页面初始化时清空历史
  useEffect(() => {
    storage.remove("chatHistory");
    setMessages([]);
  }, []);

  // 滚动到底部
  useEffect(() => {
    if (scrollRef.current) {
      scrollRef.current.scrollTo({ scrollTop: 99999, duration: 300 });
    }
  }, [messages, typing, typeText]);

  const saveHistory = (history: any[]) => {
    storage.set("chatHistory", history);
  };

  const loadHistory = () => {
    return storage.get("chatHistory") || [];
  };

  const handleSend = async () => {
    if (!input.trim() || typing) return;

    const userMsg = { role: "user" as const, text: input };
    setMessages((msgs) => [...msgs, userMsg]);
    setTyping(true);

    // 插入“思考中...”占位
    const loadingIndex = messages.length + 1;
    setMessages((msgs) => [
      ...msgs,
      { role: "bot", text: "思考中...", loading: true },
    ]);

    try {
      const token = generateToken(apiKey);

      // ✅ 取本地历史，加入新消息
      const history = loadHistory();
      const updatedHistory = [...history, userMsg];

      const requestBody = {
        id: appid,
        input: {
          BOT_CHAT_HISTORY: updatedHistory,
          BOT_USER_INPUT: input,
          BOT_USER_FILE: null,
        },
        type: 1,

        history: updatedHistory,
      };

      const res: any = await axios.post(url, requestBody, {
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        },
      });

      const replyText = res.data.data.output;

      startType(replyText, () => {
        setMessages((msgs) => {
          const copy = [...msgs];
          copy[loadingIndex] = { role: "bot", text: replyText };

          // ✅ 保存历史（包含 bot 回复）
          const newHistory = [
            ...updatedHistory,
            { role: "bot", text: replyText },
          ];
          saveHistory(newHistory);

          return copy;
        });
        setTyping(false);
      });
    } catch (error: any) {
      const errMsg = "请求失败：" + (error.message || "未知错误");
      setMessages((msgs) => {
        const copy = [...msgs];
        copy[loadingIndex] = { role: "bot", text: errMsg };

        // 保存错误消息
        const newHistory = [
          ...loadHistory(),
          userMsg,
          { role: "bot", text: errMsg },
        ];
        saveHistory(newHistory);

        return copy;
      });
      setTyping(false);
    }

    setInput("");
  };

  const handleBack = () => {
    Taro.navigateTo({ url: "/pages/index/index" });
  };

  return (
    <View className="chat-page">
      <View className="chat-header">
        <AtIcon
          value="chevron-left"
          size="24"
          color="#fff"
          onClick={handleBack}
          className="back-icon"
        />
      </View>

      <ScrollView ref={scrollRef} scrollY className="chat-list">
        {messages.map((msg, idx) => (
          <View
            key={idx}
            className={`chat-msg ${msg.role} ${msg.loading ? "loading" : ""}`}
          >
            {msg.loading ? (
              <View className="dot-loading">
                <View className="dot"></View>
                <View className="dot"></View>
                <View className="dot"></View>
              </View>
            ) : (
              msg.text
            )}
          </View>
        ))}
        {typing && !messages[messages.length - 1]?.loading && (
          <View className="chat-msg bot">{typeText}</View>
        )}
      </ScrollView>

      <View className="chat-input-bar">
        <Input
          className="chat-input"
          value={input}
          onInput={(e) => setInput(e.detail.value)}
          onConfirm={handleSend}
          placeholder="请输入你的问题..."
          disabled={typing}
        />
        <Button
          className="chat-send"
          onClick={handleSend}
          disabled={typing || !input.trim()}
        >
          发送
        </Button>
      </View>
    </View>
  );
}
